#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <unistd.h>
#include <time.h>
#include "des.h"

#define AS_PORT 12345

char K_Client[] = "INClient";
char K_TGS[] = "INTGS000";
char Ksession_Client_TGS[] = "Session1";

char *ClientID = "xinghanting";

void serve(struct sockaddr_in *clientAddr, int client)
{
    int iDataNum = -1;
    int messageLen;
    char buffer[150]; //buffer 负责存放Client发来的数据

    //inet_ntoa ip地址转换函数，将网络字节序IP转换为点分十进制IP
    //表达式：char *inet_ntoa (struct in_addr);
    printf("IP is %s\n", inet_ntoa(clientAddr->sin_addr));
    printf("Port is %d\n", htons(clientAddr->sin_port));
    printf("等待消息...\n");

    printf("开始读取消息\n");
    //初始化缓冲区
    while (iDataNum < 0)
    {
        iDataNum = recv(client, buffer, 200, 0);
    }
    buffer[iDataNum] = '\0';
    if (strcmp(buffer, "quit") == 0)
        return;
    printf("获取用户ID为 %s\n", buffer);

    //检测用户的ID是否正确
    if (strcmp(buffer, ClientID) != 0)
    {
        printf("ClientID is wrong\n");
        send(client, "Please give me correct ID", strlen("Please give me correct ID"), 0);
        return;
    }
    else
    {
        printf("Client ID is right\n");
    }

    //如果ID正确，那么AS将会发给client两条信息A和B
    //A是使用K_Client加密的Ksession_Client_TGS
    //B是使用K_TGS加密的票据TGT
    //TGT的组成包括客户ID、客户网络地址、票据有效期、Ksession_Client_TGS
    
    //生成发送A
    char A[100];
    messageLen = des(K_Client,Ksession_Client_TGS,strlen(Ksession_Client_TGS),A);
    printf("发送消息A 消息A的明文是%s\n",Ksession_Client_TGS);
    send(client,A,messageLen,0);

    //A和B之间的发送间隔2秒，确保客户端有时间接收
    sleep(2);

    //生成发送B
    char tempB[200];
    char B[200];
    sprintf(tempB,"<%s,%s,%ld,%s>",ClientID,inet_ntoa(clientAddr->sin_addr),time(NULL)+1231232,Ksession_Client_TGS);
    printf("发送加密的消息B 消息B的明文是");
    printf("%s\n",tempB);
    messageLen = des(K_TGS,tempB,strlen(tempB),B);
    // printBase64(B);
    send(client,B,messageLen,0);
    printf("----------AS发送消息完成----------\n");
}

int main(int argc, char *argv[])
{
    srand(time(NULL)+1);
    int client;
    int ASsocket;
    pid_t pid;
    int addr_len = sizeof(struct sockaddr_in);
    struct sockaddr_in AServer_addr;

    // socket函数，失败返回-1
    // int socket(int domain, int type, int protocol);
    // 第一个参数表示使用的地址类型，一般都是ipv4，AF_INET
    // 第二个参数表示套接字类型：tcp：面向连接的稳定数据传输SOCK_STREAM
    // 第三个参数设置为0
    if ((ASsocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        printf("Create socket error!\n");
        return 1;
    }
    else
    {
        printf("Socket number = %d\n", ASsocket);
    }

    //初始化服务器端的地址
    bzero(&AServer_addr, sizeof(AServer_addr));
    AServer_addr.sin_family = AF_INET;                //TCP/IP协议
    AServer_addr.sin_port = htons(AS_PORT);           //绑定端口号，htons即host-to-network
    AServer_addr.sin_addr.s_addr = htonl(INADDR_ANY); //服务器接受的任意内外网IP

    if (bind(ASsocket, (struct sockaddr *)&AServer_addr, sizeof(AServer_addr)) < 0)
    {
        perror("connect");
        return 0;
    }
    else
    {
        printf("bind succeed\n");
    }

    listen(ASsocket, 100);
    printf("AS is Listening %d\n", AS_PORT);
    while (1)
    {
        // 调用accept函数后，会进入阻塞状态
        // accept返回一个套接字的文件描述符，这样服务器端便有两个套接字的文件描述符，
        // serverSocket和client。
        // serverSocket仍然继续在监听状态，client则负责接收和发送数据
        // clientAddr是一个传出参数，accept返回时，传出客户端的地址和端口号
        // addr_len是一个传入-传出参数，传入的是调用者提供的缓冲区的clientAddr的长度，以避免缓冲区溢出。
        // 传出的是客户端地址结构体的实际长度。
        // 出错返回-1

        struct sockaddr_in ClientAddr;
        client = accept(ASsocket, (struct sockaddr *)&ClientAddr, (socklen_t *)&addr_len);
        // printf("client is %d\n", client);
        if (client > 0)
        {
            printf("we have a new client\n");
        }
        pid = fork();
        if (pid == 0)
        { //返回子进程
            serve(&ClientAddr, client);
            return 0;
        }
    }
    close(ASsocket);
    return 0;
}
